package main

// 结构体有个简写方法 如果是指针 在调用的时候可以省略* 不过底层也是通过*实现的

// 首字母小写包内可见 大写包外也可见

// golang没有类这个概念，可以用结构体仿类

// 封装多个数据类型的集合

// 定义类型别名
// type myInt = int

// 同一个包内结构体名字不能重复，同一个结构体内属性名字不能重复
// 定义结构体属性后面不需要，
// 定义1
// type Sa struct {
// 	Name string
// 	Age  float32
// }

// 定义2 结构体方法
// type Sa2 struct {
// 	Name string
// 	Age  int
// }

// // 除了 (a Sa2) 其它和方法完全一样
// func (a Sa2) say() {
// 	a.Name = "admin123" // 传的是值改了没啥用 就对下面有用外边无用
// 	fmt.Printf("%#v", a)
// }

// type Sa2 struct {
// 	Name string
// 	Age  int
// }

// // 除了 (a Sa2) 其它和方法完全一样
// func (a *Sa2) say() {
// 	a.Name = "admin123" // 这里是简写相当于(*a).所以改的是地址上的值外边也变了
// 	fmt.Printf("%#v", a)
// }

// 自定义类型定义方法
// type myInt int

// func (m myInt) say() {
// 	fmt.Println(m)
// }

// 结构体匿名字段 类型必须唯一
// type Nm struct {
// 	string
// 	int
// }

// 结构体是切片map
// type SM struct {
// 	S []string
// 	M map[string]string
// }

// 结构体嵌套
// type S1 struct {
// 	Name string
// }

// type S2 struct {
// 	k S1
// }
// 结构体嵌套匿名结构体
// type S2 struct {
// 	S1 // 这样写相当于S1 S1
// }

// 结构体嵌套字段冲突 父结构体和子结构体名称一样时 访问的是父结构体的属性  【多个子结构体（匿名结构体）名字一样就冲突了父结构体没有该属性 使用简写就不知道找谁了所以要带着子结构体类型名字访问属性】 具名的通过属性名字访问相同的属性 冲突指的是简写的属性只写结构体类型 如果不想访问默认的想访问子结构体就带着子结构体名字访问属性
// 好比上个定义

// 结构体继承是通过结构体的嵌套实现的
// type P struct {
// 	Name string
// }

// func (a P) say() {
// 	fmt.Println("fu")
// }

// type C struct {
// 	P   // 继承这里相当于 P P
// 	Age int
// }

// 嵌套结构体指针
// type C struct {
// 	P *P //也是可以的注意使用的时候赋值要给他地址
// } 赋值的时候需要 C{p:&P{}}

func main() {
	// 结构体是值类型的
	// %T main.type名字

	// var a myInt = 1
	// fmt.Printf("%v,%T", a, a) // 类型是实际上的int而不是别名 注意和自定义类型区别如果是自定义类型这里是 main.myInt

	// 实例化
	// 1
	// var a Sa
	// a = Sa{
	// 	Name: "admin",
	// 	Age:  12,
	// }
	// fmt.Printf("%#v,%v", a, a.Name) // 打印结构体详细信息%#v main.Sa{Name:"admin", Age:12}

	// 2
	// var a Sa // 值类型上来声明后可以直接赋值
	// a.Name = "admin"
	// //没赋值的成员就是类型默认值
	// fmt.Printf("%#v", a)

	// 3 因为是值类型可以用指针所以可以拿指针类型来接
	// var a *Sa   // 获取指针，但是值类型默认也没有开辟内存空间 无法直接用*a 所以申请内存空间
	// a = new(Sa) // 申请内存空间
	// (*a).Name = "admin"
	// fmt.Printf("%#v", *a) // 获取地址对应的值

	// 4 省略 * 的写法 %T *main.Sa
	// var a *Sa
	// a = new(Sa)
	// a.Name = "aaaddd"          // 结构体指针调用值可以直接省略*
	// fmt.Printf("%#v,%T", a, a) // 结构体指针调用值可以直接省略*
	// fmt.Println("====")

	// 5 直接使用&初始化赋值 注意赋值的目标也是指针 *main.Sa
	// as := &Sa{
	// 	Name: "name",
	// 	Age:  12,
	// }

	// fmt.Printf("%#v,%#v,%T", as, *as, as)

	// 6 声明+初始化 main.Sa 非指针类型
	// as := Sa{
	// 	Name: "aa",
	// 	Age:  12,
	// } // 普通值类型
	// fmt.Printf("%#v,%#v,%T", as, as, as)

	// 7 初始化，有些字段不赋值，默认用默认类型的默认值！！！

	// 8 初始化的时候，不指定key名字，按照顺序初始化。 main.Sa{Name:"aa", Age:33},main.Sa{Name:"aa", Age:33},main.Sa 顺序和上面定义结构体一一对应
	// as := Sa{
	// 	"aa",
	// 	33,
	// }
	// fmt.Printf("%#v,%#v,%T", as, as, as)

	// 结构体方法的实例先来个值的
	// a := Sa2{
	// 	Name: "aaa",
	// 	Age:  12,
	// }
	// a.say()
	// fmt.Printf("%#v,%#v,%T", a, a, a)

	// 结构体方法的实例地址的
	// a := Sa2{
	// 	Name: "aaa",
	// 	Age:  12,
	// }
	// a.say()
	// fmt.Printf("%#v,%#v,%T", a, a, a)

	// Sa{}多个彼此独立 即便指针也不互相影响 和类同

	// 自定义类型方法
	// var a myInt = 1
	// a.say()

	// 只能给自己包的自定义类型定义方法不能给系统包的类型添加方法 type后的类型可以定义方法

	// 结构体匿名字段 类型必须唯一 main.Nm{string:"123", int:1},main.Nm{string:"123", int:1},main.Nm
	// as := Nm{
	// 	"123",
	// 	1,
	// }
	// fmt.Printf("%#v,%#v,%T", as, as, as)

	// 结构体是切片map main.SM{S:[]string{"", "", "", ""}, M:map[string]string{}},main.SM{S:[]string{"", "", "", ""}, M:map[string]string{}},main.SM
	// as := SM{
	// 	S: make([]string, 4, 4),
	// 	M: make(map[string]string),
	// }
	// fmt.Printf("%#v,%#v,%T", as, as, as)

	// 结构体嵌套 main.S2{k:main.S1{Name:"123"}},main.S2{k:main.S1{Name:"123"}},main.S2
	// as := S2{
	// 	k: S1{
	// 		Name: "123",
	// 	},
	// }
	// var as S2
	// as.k.Name = "aaaa"
	// fmt.Printf("%#v,%#v,%T", as, as, as)

	// 嵌套匿名结构体调用
	// var as S2
	// as.Name = "aaaaa" // 先找S2结构体的属性没有在去匿名嵌套结构体找
	// as.S1.Name = "bbb"
	// fmt.Printf("%#v,%#v,%T", as, as, as)

	// 结构体继承是通过结构体的嵌套实现的
	// as := C{
	// 	Age: 123,
	// }
	// as.say()
	// fmt.Printf("%#v,%#v,%T", as, as, as)

}
